/*
    This file is part of Posixcpp library.

    Posixcpp library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Posixcpp library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU LesserGeneral Public
    License along with Posixcpp library. If not, see
    <http://www.gnu.org/licenses/>.
*/

/**
 * @file posix_mutex.hpp
 * @brief POSIX mutex and related datatypes
 */

#ifndef POSIX_THREADS_MUTEX_INCLUDED
#define POSIX_THREADS_MUTEX_INCLUDED

#include <pthread.h>
#include <ostream>

#include "posix_time_timespec.hpp"
#include "posix_threads_ilock.hpp"

namespace posix
{
namespace threads
{
/**
 * @brief POSIX mutex
 */
class Mutex : public ILock
{
public:
	/**
     * @brief Mutex types
     */
    enum class Type_t
	{
		NORMAL = PTHREAD_MUTEX_NORMAL,
		RECURSIVE = PTHREAD_MUTEX_RECURSIVE,
		SAFE = PTHREAD_MUTEX_ERRORCHECK
	};

    class Attributes
	{
	public:
		Attributes();
		Attributes( Type_t type, int priorityCeiling );
		~Attributes();
		
        pthread_mutexattr_t & handle() { return m_handle; }
		const pthread_mutexattr_t & handle() const { return m_handle; }
		
		/**
		 * @property Type_t type
		 * 
		 * Type of the mutex. Balance between speed and bug detection
		 * simplicity
         */
		
		void setType(Type_t newVal);
		Mutex::Type_t type();
		
		/**
		 * @property int priorityCeiling
         * 
		 * Thread scheduling priority ceiling for mutex
         */
		
		void setPriorityCeiling( int newVal );
		int getPriorityCeiling();
		
    private:
		pthread_mutexattr_t m_handle;
	};

	Mutex();
	Mutex(const Attributes & attributes);
	~Mutex();

	void lock();
	bool lock(time::Timespec timeout);
	bool tryLock();
	void unlock();

	pthread_mutex_t & handle() { return m_handle; }
	const pthread_mutex_t & handle() const { return m_handle; }
private:
	pthread_mutex_t m_handle;
};

std::ostream & operator<<(std::ostream & stream, posix::threads::Mutex::Type_t data);
}
}
#endif // POSIX_THREADS_MUTEX_INCLUDED
